﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sheeps
{
    public class MxSheepBehavior : SheepBehaviorAlogorithm
    {
        const double BORDER_ANGLE = Math.PI / 2;
        const double MOVE_FORWARD_WEIGHT = 0.7;
        const double MOVE_TOWARD_CENTER_WEIGHT = 1 - MOVE_FORWARD_WEIGHT;
        const double RUN_AWAY_WEIGHT = 0.4;
        
        public double RandomMoveWeight {get; set;}

        private Random randomizer;

        public bool DoRandom { get; set; }

        protected Vector3 GetRandomVector()
        {
            double randX = (randomizer.NextDouble() - 0.5) * 2; //-1 ; 1
            double randY = (randomizer.NextDouble() - 0.5) * 2;
            return new Vector3(randX, randY, 0);
        }

        protected Vector3 NormalizeAndAddRandomIfNeededAndNormalize(Vector3 movementVector)
        {
            movementVector.Normalize();
            if (this.DoRandom)
            {
                Vector3 randV = this.GetRandomVector();
                movementVector += randV * RandomMoveWeight;
            }
            movementVector.Normalize();
            return movementVector;
        }

        /// <summary>
        /// Sends sheep away from dog
        /// </summary>
        /// <param name="sheep"></param>
        /// <param name="dog"></param>
        protected virtual void MoveSheepInBack(Sheep sheep, Dog dog)
        {
            Vector3 ds = sheep.Position - dog.Position;
            ds = this.NormalizeAndAddRandomIfNeededAndNormalize(ds);
            ds = ds * sheep.MaxMoveLength;
            sheep.Position += ds * RUN_AWAY_WEIGHT;
        }

        protected virtual void MoveSheepInFront(Sheep sheep, Dog dog, Vector3 flockCenterPoint)
        {
            Vector3 forwardOffest = dog.NormalizedOrientation * MOVE_FORWARD_WEIGHT;
            Vector3 centerOffest = (flockCenterPoint - sheep.Position);
            centerOffest.Normalize();
            centerOffest = centerOffest * MOVE_TOWARD_CENTER_WEIGHT;
            Vector3 offset = forwardOffest + centerOffest;
            offset = this.NormalizeAndAddRandomIfNeededAndNormalize(offset);
            sheep.Position += offset * sheep.MaxMoveLength;



        }

        protected virtual void MoveNotScaredSheep(Sheep sheep)
        {
            if (this.DoRandom)
            {
                Vector3 randV = this.GetRandomVector() * RandomMoveWeight * sheep.MaxMoveLength;
                sheep.Position += randV;
            }
        }

        public override void UpdatePositions(GameState gameState)
        {
            var dog = gameState.Dog;

            //var scaredSheepList = from sheep in gameState.SheepList
            //                      where sheep.Position.Distance(gameState.Dog.Position) < sheep.Sensibility
            //                      select sheep;

            //var scaredSheepInFront = from sheep in scaredSheepList
            //                        where dog.NormalizedOrientation.Angle(sheep.Position - dog.Position) < BORDER_ANGLE
            //                        select sheep;

            //var scaredSheepInBack = from sheep in scaredSheepList
            //                        where dog.NormalizedOrientation.Angle(sheep.Position - dog.Position) >= BORDER_ANGLE
            //                        select sheep;

            Vector3 flockCenterPoint = dog.Position + dog.NormalizedOrientation * dog.MaxMoveLength;
            //move sheep
            foreach (var sheep in gameState.SheepList)
            {
                if (gameState.IsSheepInPen(sheep))
                {
                    continue;
                }

                if (sheep.Position.Distance(gameState.Dog.Position) < sheep.Sensibility)
                {
                    if (dog.NormalizedOrientation.Angle(sheep.Position - dog.Position) >= BORDER_ANGLE)
                    {
                        this.MoveSheepInBack(sheep, dog);
                    }
                    else
                    {
                        this.MoveSheepInFront(sheep, dog, flockCenterPoint);
                    }
                }
                else
                {
                    this.MoveNotScaredSheep(sheep);
                }
                if (sheep.Position.X < 0)
                {
                    sheep.Position = new Vector3(-sheep.Position.X, sheep.Position.Y, 0);                
                }
                if (sheep.Position.X > gameState.Width)
                {
                    sheep.Position = new Vector3(2 * gameState.Width - sheep.Position.X, sheep.Position.Y, 0);
                }
                if (sheep.Position.Y < 0)
                {
                    sheep.Position = new Vector3(sheep.Position.X, -sheep.Position.Y, 0);
                }
                if (sheep.Position.Y > gameState.Height)
                {
                    sheep.Position = new Vector3(sheep.Position.X, 2 * gameState.Height - sheep.Position.Y, 0);
                }
            }
        }

        public MxSheepBehavior()
        {
            this.DoRandom = true;
            this.randomizer = new Random();
            this.RandomMoveWeight = 0.3;
        }
    }
}
